﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using DataBroker.Criteria;
using DataBroker.Dal;
using DataBroker.Dao;
using NorthwindDAO;

namespace ConsoleTests
{
    public class Program
    {
        private static ManualResetEvent[] mre1;
        private static ManualResetEvent[] mre2;

        static void FirstTransaction(object dummy)
        {
            D2Bk.LogDebug("Entering First Transaction");
            try
            {
                D2Bk.ChangeDatabase("Northwind");
                Filter f = new Filter();
                f.Add("Customerid", "ALFKI");
                List<Entity> alfki = D2Bk.Fetch(f, new Customers());

                int current = 0;
                if (int.TryParse(((Customers) alfki[0]).Contacttitle, out current))
                {
                    if (current != ((int) dummy) - 1)
                        D2Bk.LogWarn("Expected: {0}; Actual: {1}", ((int)dummy) - 1, current);
                }

                ((Customers)alfki[0]).Contacttitle = dummy.ToString();

                D2Bk.BeginTransaction();
                int affected = D2Bk.SaveOne(alfki[0]);
                if (affected < 1)
                    D2Bk.LogError("!!!!  Didn't update customers !!!!!");

                
                if (affected < 1)
                    D2Bk.LogError("!!!!  Didn't update Typee !!!!!");
                
                Filter emp = new Filter();
                emp.Add("Employeeid", 1);
                List<Entity> empl = D2Bk.Fetch(new Filter(), new Employees());
                if (empl == null)
                    D2Bk.LogError("!!!!  Didn't get customers !!!!!");
                D2Bk.Commit();
                int dumint = int.Parse(dummy.ToString());
                mre1[dumint].Set();
            }
            catch (Exception ex)
            {
                D2Bk.LogError("{0} {1}", ex.Message, ex.StackTrace);
                if (ex.InnerException != null)
                    D2Bk.LogError("{0} {1}", ex.InnerException.Message, ex.InnerException.StackTrace);
            }
        }

        static void SecondTransaction(object dummy)
        {
            D2Bk.ChangeDatabase("Northwind");
            Filter emp = new Filter();
            emp.Add("Employeeid", 1);
            List<Entity> empl = D2Bk.Fetch(emp, new Employees());

            //((Customers)alfki[0]).Contacttitle = "cont";
            ((Employees)empl[0]).Titleofcourtesy = dummy.ToString();


            D2Bk.BeginTransaction();
            int affected = D2Bk.SaveOne(empl[0]);

            if (affected < 1)
                D2Bk.LogError("!!!!  Didn't update employees !!!!!");

            Filter f = new Filter();
            f.Add("Customerid", "ALFKI");
            List<Entity> alfki = D2Bk.Fetch(new Filter(), new Customers());
            if (alfki == null)
                D2Bk.LogError("!!!!  Didn't get customers !!!!!");
            D2Bk.LogDebug("Setting for first");
            D2Bk.Rollback();
            int dumint = int.Parse(dummy.ToString());
            mre2[dumint].Set();
        }

        static void DeadlockRecovery()
        {
            const int handles = 63;

            mre1 = new ManualResetEvent[handles];
            mre2 = new ManualResetEvent[handles];
            for (int i = 0; i < handles; i++)
            {
                mre1[i] = new ManualResetEvent(false);
                mre2[i] = new ManualResetEvent(false);
            }
            for (int i = 0; i < handles; i++)
            {
                ThreadPool.QueueUserWorkItem(FirstTransaction, i);
                ThreadPool.QueueUserWorkItem(SecondTransaction, i);
            }
            WaitHandle.WaitAll(mre1);
            WaitHandle.WaitAll(mre2);
        }

        static void DeadlockRecovery2()
        {
            for (int i = 1; i < 100; i++)
            {
                ThreadPool.QueueUserWorkItem(FirstTransaction);
                ThreadPool.QueueUserWorkItem(SecondTransaction);
            }
        }

        static void ThirdTransaction(object dummy)
        {
            D2Bk.ChangeDatabase("Northwind");
            Filter f = new Filter();
            f.Add("Customerid", "ALFKI");
            List<Entity> alfki = D2Bk.Fetch(f, new Customers());

            ((Customers)alfki[0]).Contacttitle = "cont";
            D2Bk.BeginTransaction();
            int affected = D2Bk.SaveOne(alfki[0]);
            if (affected < 1)
                D2Bk.LogError("!!!!  Didn't update customers !!!!!");
            Filter emp = new Filter();
            emp.Add("Employeeid", 1);
            List<Entity> empl = D2Bk.Fetch(new Filter(), new Employees());
            if (empl == null)
                D2Bk.LogError("!!!!  Didn't get customers !!!!!");
            D2Bk.Commit();
        }

        static D2BkUOW uow = new D2BkUOW(typeof(Program).GetMethod("CallDyn"),
                          new ICloneable[] { new Customers(), "a message" });

        public static int CallDyn(Entity e, string b)
        {
            D2Bk.LogDebug("Values: {0}, {1}",e,b);
            throw new Exception("Oh goodnes");
            return 1;
        }

         static void TestCall(object dummy)
         {
             D2Bk.LogDebug("called!");
             object result = uow.Execute();
         }

         static void Main(string[] args)
         {
             D2Bk.ChangeDatabase("Northwind");
             Filter f = new Filter();
             f.Add("Fax", Operator.IsNull);
             List<Entity> customers = D2Bk.Fetch(f, new Customers());
         }
         
        static void Main1(string[] args)
        {
            DeadlockRecovery();
        }

        private static void TestRefl()
        {
            D2Bk.ChangeDatabase("Northwind");
            D2Bk.BeginTransaction(); 
            Filter f = new Filter();
            f.Add("Customerid", "ALFKI");
            List<Entity> alfki = D2Bk.Fetch(f, new Customers());
            ((Customers)alfki[0]).Contacttitle = "cont";
            Filter emp = new Filter();
            emp.Add("Employeeid", 1);
            List<Entity> empl = D2Bk.Fetch(new Filter(), new Employees());
            if (empl == null)
                D2Bk.LogError("!!!!  Didn't get customers !!!!!");
            ((Employees)empl[0]).Titleofcourtesy = "cort";
            int affected = D2Bk.SaveOne(alfki[0]);
            if (affected < 1)
                D2Bk.LogError("!!!!  Didn't update customers !!!!!");
            D2Bk.SaveOne(empl[0]);
            D2Bk.Rollback(false);


            foreach (D2BkUOW uow in D2Bk.UnitOfWork)
            {
                uow.Execute();
            }

            D2Bk.Rollback();

        }
    }
}
